package rifl.meres4.ui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JOptionPane;

import org.osgi.service.log.LogService;

import rifl.meres4.commons.step.IWorkflowStep;
import rifl.meres4.commons.ui.AbstractGUI;
import rifl.meres4.commons.ui.StepFrame;
import rifl.meres4.development.step.IArchitectureStep;
import rifl.meres4.development.step.IImplementationStep;
import rifl.meres4.development.step.IIntegrationStep;
import rifl.meres4.development.step.ISpecificationStep;
import rifl.meres4.development.step.IUIImplementationStep;
import rifl.meres4.release.step.IReleaseStep;
import rifl.meres4.release.step.IRepairStep;
import rifl.meres4.release.step.ITestStep;
import rifl.meres4.release.step.impl.TestStep;

public class WorkflowUI extends AbstractGUI {

	// development ui frames
	private SpecificationStepFrame specificationStepFrame;
	private StepFrame architectureStepFrame;
	private StepFrame implementationFrame;
	private StepFrame uiFrame;
	private StepFrame integrationFrame;
	private StepFrame testFrame;
	private StepFrame repairFrame;
	private StepFrame releaseFrame;	
	
	// development services
	private ISpecificationStep specificationStep;
	private IArchitectureStep architectureStep;
	private IImplementationStep implementationStep;
	private IUIImplementationStep uiImplementationStep;
	private IIntegrationStep integrationStep;
	private ITestStep testStep;
	private IRepairStep repairStep;
	private IReleaseStep releaseStep;	
	
	@Override
	protected void initializeGUI() {
		specificationStepFrame = new SpecificationStepFrame("Step1: Specification", true, 0, 200);
		architectureStepFrame = new StepFrame("Step2: Architecure Design", 400, 200);
		implementationFrame = new StepFrame("Step3a: Implementation", 800,0);
		uiFrame = new StepFrame("Step3b: GUI implementation", 800, 400);
		integrationFrame = new StepFrame("Step4: Integration", 1200, 200);
		testFrame = new StepFrame("If block: Testing", 1200, 600);
		repairFrame = new StepFrame("Step4e: Repair", 800, 600);
		releaseFrame = new StepFrame("Step5: Release", 400, 600);
		
		// add button listeners for handling manual control of the flow
		specificationStepFrame.getNextButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				callStep(specificationStepFrame, specificationStep);
			}
		});
		architectureStepFrame.getNextButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				callStep(architectureStepFrame, architectureStep);
			}
		});
		implementationFrame.getNextButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				callStep(implementationFrame, implementationStep);
			}
		});
		uiFrame.getNextButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				callStep(uiFrame, uiImplementationStep);
			}
		});
		integrationFrame.getNextButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				callStep(integrationFrame, integrationStep);
			}
		});
		testFrame.getNextButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				callStep(testFrame, testStep);
			}
		});
		repairFrame.getNextButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				callStep(repairFrame, repairStep);
			}
		});
		releaseFrame.getNextButton().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				callStep(releaseFrame, releaseStep);
			}
		});
	}
	
	@Override
	protected void preCallStep(StepFrame stepFrame, IWorkflowStep workflowStep) {	
		if (!(stepFrame instanceof SpecificationStepFrame)) {
			stepFrame.getNextButton().setEnabled(false);				
		}
		if (workflowStep instanceof ITestStep) {
			/**
			 * User decision: if tests were successful, then the next step will be 'Release Step'.
			 * 				  Otherwise, next step is 'Repair Step', and 'Release Step' comes after it.
			 */			
			switch (JOptionPane.showConfirmDialog(testFrame, "Tests succcessful?", "Tests succcessful?", JOptionPane.YES_NO_OPTION)) {
			case JOptionPane.YES_OPTION: 
				//((TestStep) workflowStep).testSuccessful = true;
				((ITestStep) workflowStep).setTestSuccess(true);
				break;
			default: 
				//((TestStep) workflowStep).testSuccessful = false;
				((ITestStep) workflowStep).setTestSuccess(false);
				break;
			}
		}
	}
	
	public void setSpecificationStep(ISpecificationStep specificationStep) {
		if (this.log != null) {
			this.log.log(LogService.LOG_INFO, "Specification Service available!");
		}
		this.specificationStep = specificationStep;
		this.specificationStepFrame.getNextButton().setEnabled(true);
		String prevText = this.specificationStepFrame.getTextArea().getText();
		this.specificationStepFrame.getTextArea().setText(prevText + "\n-----\nService available!\n-----\n");	
	}
	
	public void unsetSpecificationStep(ISpecificationStep specificationStep) {
		if (this.log != null) {
			this.log.log(LogService.LOG_INFO, "Specification Service available!");
		}
		if (this.specificationStep == specificationStep) {
			this.specificationStep = null;
			this.specificationStepFrame.getNextButton().setEnabled(false);
			String prevText = this.specificationStepFrame.getTextArea().getText();
			this.specificationStepFrame.getTextArea().setText(prevText + "\n-----\nService Unavailable!\n-----\n");
		}
	}
	
	public void setArchitectureStep(IArchitectureStep architectureStep) {
		this.architectureStep = architectureStep;
		register(architectureStep, architectureStepFrame);
	}
	
	public void unsetArchitectureStep(IArchitectureStep architectureStep) {
		if (this.architectureStep == architectureStep) {
			this.architectureStep = null;
			unregister(architectureStep, architectureStepFrame);
		}
	}

	public void setImplementationStep(IImplementationStep implementationStep) {
		this.implementationStep = implementationStep;
		register(implementationStep, implementationFrame);
	}
	
	public void unsetImplementationStep(IImplementationStep implementationStep) {
		if (this.implementationStep == implementationStep) {
			this.implementationStep = null;
			unregister(implementationStep, implementationFrame);
		}
	}
	
	public void setUiImplementationStep(
			IUIImplementationStep uiImplementationStep) {
		this.uiImplementationStep = uiImplementationStep;
		register(uiImplementationStep, uiFrame);
	}
	
	public void unsetUiImplementationStep(
			IUIImplementationStep uiImplementationStep) {
		if (this.uiImplementationStep == uiImplementationStep) {
			this.uiImplementationStep = null;
			unregister(uiImplementationStep, uiFrame);
		}
	}
	
	public void setIntegrationStep(IIntegrationStep integrationStep) {
		this.integrationStep = integrationStep;
		register(integrationStep, integrationFrame);
	}
	
	public void unsetIntegrationStep(IIntegrationStep integrationStep) {
		if (this.integrationStep == integrationStep) {
			this.integrationStep = null;
			unregister(integrationStep, integrationFrame);
		}
	}
	
	public void setTestStep(ITestStep testStep) {
		this.testStep = testStep;
		register(testStep, testFrame);
	}
	
	public void unsetTestStep(ITestStep testStep) {
		if (this.testStep == testStep) {
			this.testStep = null;
			unregister(testStep, testFrame);
		}
	}

	public void setRepairStep(IRepairStep repairStep) {
		this.repairStep = repairStep;
		register(repairStep, repairFrame);
	}
	
	public void unsetRepairStep(IRepairStep repairStep) {
		if (this.repairStep == repairStep) {
			this.repairStep = null;
			unregister(repairStep, repairFrame);
		}
	}
	
	public void setReleaseStep(IReleaseStep releaseStep) {
		this.releaseStep = releaseStep;
		register(releaseStep, releaseFrame);
	}
	
	public void unsetReleaseStep(IReleaseStep releaseStep) {
		if (this.releaseStep == releaseStep) {
			this.releaseStep = null;
			unregister(releaseStep, releaseFrame);
		}
	}

	@Override
	protected void disposeGUI() {
		specificationStepFrame.setVisible(false);
		specificationStepFrame.dispose();
		architectureStepFrame.setVisible(false);
		architectureStepFrame.dispose();
		implementationFrame.setVisible(false);
		implementationFrame.dispose();
		uiFrame.setVisible(false);
		uiFrame.dispose();
		integrationFrame.setVisible(false);
		integrationFrame.dispose();
		testFrame.setVisible(false);
		testFrame.dispose();
		repairFrame.setVisible(false);
		repairFrame.dispose();
		releaseFrame.setVisible(false);
		releaseFrame.dispose();
	}

}
